package cn.good.yan.service.t11;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * 11.AQS
 * StampedLock 读写锁的升级 （邮戳锁） - 新版本的 - （乐观锁）
 * StampedLock = ReentrantReadWriteLock + 读的过程中也允许获取写锁介入
 * 缺点：不是可重入锁、不要调用中断操作
 * @author shengren.yan
 * @create 2024-04-10
 */
public class StampedLockDemo2 {

    static int number = 37;
    static StampedLock stampedLock = new StampedLock();

    // 写锁
    public void write() {
        long stamp = stampedLock.writeLock();
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程准备修改");
        try {
            number = number + 13;
        } finally {
            stampedLock.unlockWrite(stamp);
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程结束修改");
    }

    //乐观读，读的过程中也允许获取写锁介入
    public void tryOptimisticRead() {
        // 乐观读
        long stamp = stampedLock.tryOptimisticRead();
        int result = number; // 获取一下最新的值
        // 故意间隔4秒钟，很乐观认为读取中没有其它线程修改过number值，具体靠判断
        System.out.println("4秒前stampedLock.validate方法值(true无修改，false有修改)" + "\t" + stampedLock.validate(stamp));
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" + "正在读取... " + i + " 秒" +
                    "后stampedLock.validate方法值(true无修改，false有修改)" + "\t" + stampedLock.validate(stamp));
        }
        if (!stampedLock.validate(stamp)) {
            System.out.println("有人修改过------有写操作");
            stamp = stampedLock.readLock();
            try {
                System.out.println("从乐观读 升级为 悲观读");
                result = number;
                System.out.println("重新悲观读后result：" + result);
            } finally {
                stampedLock.unlockRead(stamp);
            }
        }
        System.out.println(Thread.currentThread().getName() + "\t" + " finally value: " + result);
    }


    public static void main(String[] args) {

        StampedLockDemo2 resource = new StampedLockDemo2();

        // 先乐观读
        new Thread(() -> {
            resource.tryOptimisticRead();
        }, "readThread").start();

        // 暂停2秒钟线程,读过程可以写介入，演示
        // try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }

        // 暂停6秒钟线程
        try {
            TimeUnit.SECONDS.sleep(6);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 在写锁
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "----写锁 进来");
            resource.write();
        }, "writeThread").start();
    }

}
